package com.rightrule.sequence.impl;

import com.rightrule.sequence.Sequence;
import com.rightrule.sequence.dao.SequenceDao;
import com.rightrule.sequence.dao.impl.DefaultSequenceDao;
import com.rightrule.sequence.range.SequenceRange;
import org.springframework.util.Assert;

import java.util.Objects;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author: xry
 * @version: DefaultSequence.java 2024/9/6 21:03
 */
public class DefaultSequence implements Sequence {

    private final Lock lock = new ReentrantLock();

    // 全链路压测需求
    protected volatile SequenceRange testCurrentRange;

    private SequenceDao sequenceDao;

    /**
     * 序列名称
     */
    private String name;

    /**
     * 蚂蚁常用的租户标识
     */
    private String tntInstId;

    private volatile SequenceRange currentRange;

    @Override
    public long nextValue() {
        return nextValue(1);
    }

    @Override
    public long nextValue(int size) {
        if (Objects.isNull(sequenceDao)) {
            sequenceDao = new DefaultSequenceDao();
        }
        Assert.isTrue(size <= sequenceDao.getStep(), "");
        boolean isTest = isPressTest();

        checkSequenceRange(isTest);

        long value = getSequenceRange(isTest).getBatch(size);
        // 已经超出了range，需要重设range
        if (value == -1) {
            lock.lock();
            try {
                while (true) {
                    // 再次判断是否已经over，避免其他线程已经处理
                    if (getSequenceRange(isTest).isOver()) {
                        // over则重新设置range
                        setSequenceRange(isTest);
                    }
                    value = getSequenceRange(isTest).getBatch(size);
                    if (value == -1) {
                        continue;
                    }
                    break;
                }
            } finally {
                lock.unlock();
            }
        }
        Assert.isTrue(value >= 0, "");
        return value;
    }

    // TODO 补充是否压测的utils
    private boolean isPressTest() {
        return false;
    }

    @Override
    public boolean exhaustValue() {
        lock.lock();
        try {
            if (currentRange != null) {
                // 强制设置为已用完
                currentRange.setOver(true);
            }
        } finally {
            lock.unlock();
        }
        return true;
    }

    protected void checkSequenceRange(boolean isTest) {
        if (getSequenceRange(isTest) == null) {
            lock.lock();
            try {
                if (getSequenceRange(isTest) == null) {
                    setSequenceRange(isTest);
                }
            } finally {
                lock.unlock();
            }
        }
    }

    public SequenceRange getSequenceRange(boolean isTest) {
        if (isTest) {
            return testCurrentRange;
        } else {
            return currentRange;
        }
    }

    public SequenceDao getSequenceDao() {
        return sequenceDao;
    }

    public void setSequenceRange(boolean isTest) {
        setSequenceRange(sequenceDao.nextRange(name, tntInstId), isTest);
    }

    public void setSequenceRange(SequenceRange range, boolean isTest) {
        if (isTest) {
            this.testCurrentRange = range;
        } else {
            this.currentRange = range;
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getTntInstId() {
        return tntInstId;
    }

    public void setTntInstId(String tntInstId) {
        this.tntInstId = tntInstId;
    }

    public DefaultSequence(String name) {
        this.name = name;
    }

    public DefaultSequence() {
    }
}
